﻿using Newtonsoft.Json;
using Orleans;
using Orleans.Concurrency;
using Orleans.EventSourcing;
using Orleans.EventSourcing.CustomStorage;
using Orleans.Providers;
using Orleans.Streams;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace iTool.ClusterComponent
{

    [StatelessWorker(100)]
    public abstract class iToolServiceMultipleWithIntegerKeyBase<TState, TMaster> : Orleans.Grain, iToolServiceWithIntegerKey
        where TState : class
        where TMaster : iToolServiceMultipleMasterWithIntegerKey
    {
        private long key { get; set; }
        private Type type { get; set; }

        protected Task<TState> StateAsync { get { return this.GetStateManagement(this.type); } }

        public async override Task OnActivateAsync()
        {
            this.key = this.GetPrimaryKeyLong();
            this.type = this.GetType();

            // 状态不存在则创建
            if (await this.GetStateManagement(this.type) == null)
            {
                var service = this.GrainFactory.GetGrain<TMaster>(this.key);
                var state = await service.GetStateAsync();
                if (state == null)
                {
                    throw new Exception($"{typeof(TMaster).Name } ReadStateAsync return is null error.");
                }
                await this.SetStateManagementAsync(this.GetType(), state);
            }
        }

        async Task<TState> GetStateManagement<T>(T type)
        {
            var result = GlobalStateManagementWithIntegerKey<T, TState>.ReadState(this.key);

            if (result == null)
            {
                var service = this.GrainFactory.GetGrain<TMaster>(this.key);
                var state = await service.GetStateAsync();
                if (state == null)
                {
                    return default(TState);
                    //throw new Exception($"{typeof(TMaster).Name } ReadStateAsync return is null error.");
                }
                await this.SetStateManagementAsync(this.GetType(), state);
            }

            return result == null ? default(TState) : (result as TState);
        }

        async Task SetStateManagementAsync<T>(T type, object state)
        {
            await GlobalStateManagementWithIntegerKey<T, TState>.OnActivateAsync(this.key, state);
        }
    }

    public abstract class iToolServiceMultipleMasterWithIntegerKeyBase<TState> : iToolServiceStorageProducerBase<TState>, iToolServiceMultipleMasterWithIntegerKey
        where TState : class,new()
    {
        public iToolServiceMultipleMasterWithIntegerKeyBase() : base(queueNamespace:"MultipleStateSubscribeStreamHandler")
        {

        }

        protected async Task NotifyDeactivateAsync() 
        {
           await this.SendMessageAsync("deactivate");
        }

        protected async Task NotifyChangedStateAsync(object state)
        {
            state = state ?? new TState();
            await this.SendMessageAsync(JsonConvert.SerializeObject(state));
        }

        public async override Task OnDeactivateAsync()
        {
            await this.NotifyDeactivateAsync();
            await base.OnDeactivateAsync();
        }

        public abstract Task<object> GetStateAsync();
    }

    public interface iToolServiceMultipleMasterWithIntegerKey : iToolServiceWithIntegerKey
    {
        Task<object> GetStateAsync();
    }






    [StatelessWorker(100)]
    public abstract class iToolServiceMultipleWithStringKeyBase<TState, TMaster> : Orleans.Grain, iToolServiceWithStringKey
        where TState : class
        where TMaster : iToolServiceMultipleMasterWithStringKey
    {
        private string key { get; set; }
        private Type type { get; set; }

        protected Task<TState> StateAsync { get { return this.GetStateManagement(this.type); } }

        public async override Task OnActivateAsync()
        {
            this.key = this.GetPrimaryKeyString();
            this.type = this.GetType();

            // 状态不存在则创建
            if (await this.GetStateManagement(this.type) == null)
            {
                var service = this.GrainFactory.GetGrain<TMaster>(this.key);
                var state = await service.GetStateAsync();
                if (state == null)
                {
                    throw new Exception($"{typeof(TMaster).Name } ReadStateAsync return is null error.");
                }
                await this.SetStateManagementAsync(this.GetType(), state);
            }
        }

        async Task<TState> GetStateManagement<T>(T type)
        {
            var result = GlobalStateManagementWithStringKey<T, TState>.ReadState(this.key);

            if (result == null)
            {
                var service = this.GrainFactory.GetGrain<TMaster>(this.key);
                var state = await service.GetStateAsync();
                if (state == null)
                {
                    return default(TState);
                    //throw new Exception($"{typeof(TMaster).Name } ReadStateAsync return is null error.");
                }
                await this.SetStateManagementAsync(this.GetType(), state);
            }

            return result == null ? default(TState) : (result as TState);
        }

        async Task SetStateManagementAsync<T>(T type, object state)
        {
            await GlobalStateManagementWithStringKey<T, TState>.OnActivateAsync(this.key, state);
        }
    }

    public abstract class iToolServiceMultipleMasterWithStringKeyBase<TState> : iToolServiceStorageProducerBase<TState>, iToolServiceMultipleMasterWithStringKey
        where TState : class, new()
    {
        public iToolServiceMultipleMasterWithStringKeyBase() : base(queueNamespace: "MultipleStateSubscribeStreamHandler")
        {

        }

        protected async Task NotifyDeactivateAsync()
        {
            await this.SendMessageAsync("deactivate");
        }

        protected async Task NotifyChangedStateAsync(object state)
        {
            state = state ?? new TState();
            await this.SendMessageAsync(JsonConvert.SerializeObject(state));
        }

        public async override Task OnDeactivateAsync()
        {
            await this.NotifyDeactivateAsync();
            await base.OnDeactivateAsync();
        }

        public abstract Task<object> GetStateAsync();
    }

    public interface iToolServiceMultipleMasterWithStringKey : iToolServiceWithStringKey
    {
        Task<object> GetStateAsync();
    }

}
